package com.it.data.manager

import android.util.Log
import com.it.common.utils.LogUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString
import java.io.IOException
import java.util.concurrent.TimeUnit

/**
 *  @Description：ws管理器
 *  @author：weishixiong
 *  @date：2023/4/18 17:44
 *
 */
class WebSocketManager(
    private val scope: CoroutineScope,
    val onMessage: (String) -> Unit,
    val onConnectState: (String) -> Unit
) {

    private var webSocket: WebSocket? = null

    private val client = OkHttpClient.Builder()
        .readTimeout(0, TimeUnit.MILLISECONDS) // Disable timeout for reading responses
        .build()

    private var reconnectJob: Job? = null


    fun connect(listener: WebSocketListener? = null): Job {
        return scope.launch(Dispatchers.IO) {
            while (true) {
                try {
                    var url = "";
                    LogUtil.d(TAG, "connect: $url")
                    val request = Request.Builder().url(url).build()
                    val socketListener = listener ?: createWebSocketListener()
                    client.newWebSocket(request, socketListener)
                    break
                } catch (e: Exception) {
                    delay(RECONNECT_INTERVAL_MS)
                }
            }
        }
    }

    fun disconnect() {
        webSocket?.close(STATUS_CODE_NORMAL_CLOSURE, null)
        reconnectJob?.cancel()
    }

    fun sendMessage(message: String) {
        webSocket?.send(message)
    }

    private fun createWebSocketListener(): WebSocketListener {
        return object : WebSocketListener() {

            override fun onOpen(webSocket: WebSocket, response: Response) {
                this@WebSocketManager.webSocket = webSocket
                reconnectJob?.cancel()
                LogUtil.d(TAG, "onOpen: ")
                onConnectState.invoke(CONNECT)
                initPingJob(webSocket)
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                // Handle incoming message
                LogUtil.d(TAG, "onMessage: ${text}")
                onMessage.invoke(text)
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                // Handle incoming message
                LogUtil.d(TAG, "onMessage: ${bytes}")
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                LogUtil.d(TAG, "onClosed: ${reason}")
                onConnectState.invoke(DISCONNECT)
                reconnect()

            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                LogUtil.d(TAG, "onFailure: ${t.message}")
                onConnectState.invoke(DISCONNECT)
                reconnect()

            }

            private fun reconnect() {
                LogUtil.d(TAG, "reconnect: ")
                reconnectJob = scope.launch(Dispatchers.IO) {
                    delay(RECONNECT_INTERVAL_MS)
                    connect()
                }
            }
        }
    }

    companion object {
        private const val STATUS_CODE_NORMAL_CLOSURE = 1000
        private const val RECONNECT_INTERVAL_MS = 5000L
        const val TAG = "WebSocketManager"
        const val CONNECT = "connected"
        const val DISCONNECT = "disconnect"
        const val NORMAL_CLOSURE_STATUS = 1000
    }

    fun initPingJob(webSocket: WebSocket): Job =
        scope.launch {
            while (isActive) {
                delay(30_000) // 每 30 秒发送一次 ping
                try {
                    webSocket.send("{\"type\":\"ping\"}")
                    Log.d(TAG, "initPingJob: Send ping")
                } catch (e: IOException) {
                    Log.d(TAG, "initPingJob：Failed to send ping: ${e.message}")
                    break // 关闭协程
                }
            }
        }


}
